﻿using System;
using Mono.Collections.Generic;

namespace Mono.Cecil.Cil
{
	// Token: 0x02000121 RID: 289
	internal class InstructionCollection : Collection<Instruction>
	{
		// Token: 0x06000B3D RID: 2877 RVA: 0x00006001 File Offset: 0x00004201
		internal InstructionCollection(MethodDefinition method)
		{
			this.method = method;
		}

		// Token: 0x06000B3E RID: 2878 RVA: 0x00006012 File Offset: 0x00004212
		internal InstructionCollection(MethodDefinition method, int capacity) : base(capacity)
		{
			this.method = method;
		}

		// Token: 0x06000B3F RID: 2879 RVA: 0x00031FE8 File Offset: 0x000301E8
		protected override void OnAdd(Instruction item, int index)
		{
			bool flag = index == 0;
			if (!flag)
			{
				Instruction instruction = this.items[index - 1];
				instruction.next = item;
				item.previous = instruction;
			}
		}

		// Token: 0x06000B40 RID: 2880 RVA: 0x0003201C File Offset: 0x0003021C
		protected override void OnInsert(Instruction item, int index)
		{
			bool flag = this.size != 0;
			if (flag)
			{
				Instruction instruction = this.items[index];
				bool flag2 = instruction == null;
				if (flag2)
				{
					Instruction instruction2 = this.items[index - 1];
					instruction2.next = item;
					item.previous = instruction2;
					return;
				}
				int offset = instruction.Offset;
				Instruction previous = instruction.previous;
				bool flag3 = previous != null;
				if (flag3)
				{
					previous.next = item;
					item.previous = previous;
				}
				instruction.previous = item;
				item.next = instruction;
			}
			this.UpdateDebugInformation(null, null);
		}

		// Token: 0x06000B41 RID: 2881 RVA: 0x000320AC File Offset: 0x000302AC
		protected override void OnSet(Instruction item, int index)
		{
			Instruction instruction = this.items[index];
			item.previous = instruction.previous;
			item.next = instruction.next;
			instruction.previous = null;
			instruction.next = null;
			this.UpdateDebugInformation(item, instruction);
		}

		// Token: 0x06000B42 RID: 2882 RVA: 0x000320F4 File Offset: 0x000302F4
		protected override void OnRemove(Instruction item, int index)
		{
			Instruction previous = item.previous;
			bool flag = previous != null;
			if (flag)
			{
				previous.next = item.next;
			}
			Instruction next = item.next;
			bool flag2 = next != null;
			if (flag2)
			{
				next.previous = item.previous;
			}
			this.RemoveSequencePoint(item);
			this.UpdateDebugInformation(item, next ?? previous);
			item.previous = null;
			item.next = null;
		}

		// Token: 0x06000B43 RID: 2883 RVA: 0x0003215C File Offset: 0x0003035C
		private void RemoveSequencePoint(Instruction instruction)
		{
			MethodDebugInformation debug_info = this.method.debug_info;
			bool flag = debug_info == null || !debug_info.HasSequencePoints;
			if (!flag)
			{
				Collection<SequencePoint> sequence_points = debug_info.sequence_points;
				for (int i = 0; i < sequence_points.Count; i++)
				{
					bool flag2 = sequence_points[i].Offset == instruction.offset;
					if (flag2)
					{
						sequence_points.RemoveAt(i);
						break;
					}
				}
			}
		}

		// Token: 0x06000B44 RID: 2884 RVA: 0x000321D0 File Offset: 0x000303D0
		private void UpdateDebugInformation(Instruction removedInstruction, Instruction existingInstruction)
		{
			InstructionCollection.InstructionOffsetResolver instructionOffsetResolver = new InstructionCollection.InstructionOffsetResolver(this.items, removedInstruction, existingInstruction);
			bool flag = this.method.debug_info != null;
			if (flag)
			{
				this.UpdateLocalScope(this.method.debug_info.Scope, ref instructionOffsetResolver);
			}
			Collection<CustomDebugInformation> collection;
			if ((collection = this.method.custom_infos) == null)
			{
				MethodDebugInformation debug_info = this.method.debug_info;
				collection = ((debug_info != null) ? debug_info.custom_infos : null);
			}
			Collection<CustomDebugInformation> collection2 = collection;
			bool flag2 = collection2 != null;
			if (flag2)
			{
				foreach (CustomDebugInformation customDebugInformation in collection2)
				{
					CustomDebugInformation customDebugInformation2 = customDebugInformation;
					CustomDebugInformation customDebugInformation3 = customDebugInformation2;
					StateMachineScopeDebugInformation stateMachineScopeDebugInformation = customDebugInformation3 as StateMachineScopeDebugInformation;
					if (stateMachineScopeDebugInformation == null)
					{
						AsyncMethodBodyDebugInformation asyncMethodBodyDebugInformation = customDebugInformation3 as AsyncMethodBodyDebugInformation;
						if (asyncMethodBodyDebugInformation != null)
						{
							this.UpdateAsyncMethodBody(asyncMethodBodyDebugInformation, ref instructionOffsetResolver);
						}
					}
					else
					{
						this.UpdateStateMachineScope(stateMachineScopeDebugInformation, ref instructionOffsetResolver);
					}
				}
			}
		}

		// Token: 0x06000B45 RID: 2885 RVA: 0x000322D0 File Offset: 0x000304D0
		private void UpdateLocalScope(ScopeDebugInformation scope, ref InstructionCollection.InstructionOffsetResolver resolver)
		{
			bool flag = scope == null;
			if (!flag)
			{
				scope.Start = resolver.Resolve(scope.Start);
				bool hasScopes = scope.HasScopes;
				if (hasScopes)
				{
					foreach (ScopeDebugInformation scope2 in scope.Scopes)
					{
						this.UpdateLocalScope(scope2, ref resolver);
					}
				}
				scope.End = resolver.Resolve(scope.End);
			}
		}

		// Token: 0x06000B46 RID: 2886 RVA: 0x00032364 File Offset: 0x00030564
		private void UpdateStateMachineScope(StateMachineScopeDebugInformation debugInfo, ref InstructionCollection.InstructionOffsetResolver resolver)
		{
			resolver.Restart();
			foreach (StateMachineScope stateMachineScope in debugInfo.Scopes)
			{
				stateMachineScope.Start = resolver.Resolve(stateMachineScope.Start);
				stateMachineScope.End = resolver.Resolve(stateMachineScope.End);
			}
		}

		// Token: 0x06000B47 RID: 2887 RVA: 0x000323E4 File Offset: 0x000305E4
		private void UpdateAsyncMethodBody(AsyncMethodBodyDebugInformation debugInfo, ref InstructionCollection.InstructionOffsetResolver resolver)
		{
			bool flag = !debugInfo.CatchHandler.IsResolved;
			if (flag)
			{
				resolver.Restart();
				debugInfo.CatchHandler = resolver.Resolve(debugInfo.CatchHandler);
			}
			resolver.Restart();
			for (int i = 0; i < debugInfo.Yields.Count; i++)
			{
				debugInfo.Yields[i] = resolver.Resolve(debugInfo.Yields[i]);
			}
			resolver.Restart();
			for (int j = 0; j < debugInfo.Resumes.Count; j++)
			{
				debugInfo.Resumes[j] = resolver.Resolve(debugInfo.Resumes[j]);
			}
		}

		// Token: 0x040005DD RID: 1501
		private readonly MethodDefinition method;

		// Token: 0x02000122 RID: 290
		private struct InstructionOffsetResolver
		{
			// Token: 0x170002E7 RID: 743
			// (get) Token: 0x06000B48 RID: 2888 RVA: 0x00006024 File Offset: 0x00004224
			public int LastOffset
			{
				get
				{
					return this.cache_offset;
				}
			}

			// Token: 0x06000B49 RID: 2889 RVA: 0x0000602C File Offset: 0x0000422C
			public InstructionOffsetResolver(Instruction[] instructions, Instruction removedInstruction, Instruction existingInstruction)
			{
				this.items = instructions;
				this.removed_instruction = removedInstruction;
				this.existing_instruction = existingInstruction;
				this.cache_offset = 0;
				this.cache_index = 0;
				this.cache_instruction = this.items[0];
			}

			// Token: 0x06000B4A RID: 2890 RVA: 0x00006060 File Offset: 0x00004260
			public void Restart()
			{
				this.cache_offset = 0;
				this.cache_index = 0;
				this.cache_instruction = this.items[0];
			}

			// Token: 0x06000B4B RID: 2891 RVA: 0x000324B0 File Offset: 0x000306B0
			public InstructionOffset Resolve(InstructionOffset inputOffset)
			{
				InstructionOffset result = this.ResolveInstructionOffset(inputOffset);
				bool flag = !result.IsEndOfMethod && result.ResolvedInstruction == this.removed_instruction;
				if (flag)
				{
					result = new InstructionOffset(this.existing_instruction);
				}
				return result;
			}

			// Token: 0x06000B4C RID: 2892 RVA: 0x000324F8 File Offset: 0x000306F8
			private InstructionOffset ResolveInstructionOffset(InstructionOffset inputOffset)
			{
				bool isResolved = inputOffset.IsResolved;
				InstructionOffset result;
				if (isResolved)
				{
					result = inputOffset;
				}
				else
				{
					int offset = inputOffset.Offset;
					bool flag = this.cache_offset == offset;
					if (flag)
					{
						result = new InstructionOffset(this.cache_instruction);
					}
					else
					{
						bool flag2 = this.cache_offset > offset;
						if (flag2)
						{
							int num = 0;
							for (int i = 0; i < this.items.Length; i++)
							{
								bool flag3 = this.items[i] == null;
								if (flag3)
								{
									return new InstructionOffset((i == 0) ? this.items[0] : this.items[i - 1]);
								}
								bool flag4 = num == offset;
								if (flag4)
								{
									return new InstructionOffset(this.items[i]);
								}
								bool flag5 = num > offset;
								if (flag5)
								{
									return new InstructionOffset((i == 0) ? this.items[0] : this.items[i - 1]);
								}
								num += this.items[i].GetSize();
							}
							result = default(InstructionOffset);
						}
						else
						{
							int num2 = this.cache_offset;
							for (int j = this.cache_index; j < this.items.Length; j++)
							{
								this.cache_index = j;
								this.cache_offset = num2;
								Instruction instruction = this.items[j];
								bool flag6 = instruction == null;
								if (flag6)
								{
									return new InstructionOffset((j == 0) ? this.items[0] : this.items[j - 1]);
								}
								this.cache_instruction = instruction;
								bool flag7 = this.cache_offset == offset;
								if (flag7)
								{
									return new InstructionOffset(this.cache_instruction);
								}
								bool flag8 = this.cache_offset > offset;
								if (flag8)
								{
									return new InstructionOffset((j == 0) ? this.items[0] : this.items[j - 1]);
								}
								num2 += instruction.GetSize();
							}
							result = default(InstructionOffset);
						}
					}
				}
				return result;
			}

			// Token: 0x040005DE RID: 1502
			private readonly Instruction[] items;

			// Token: 0x040005DF RID: 1503
			private readonly Instruction removed_instruction;

			// Token: 0x040005E0 RID: 1504
			private readonly Instruction existing_instruction;

			// Token: 0x040005E1 RID: 1505
			private int cache_offset;

			// Token: 0x040005E2 RID: 1506
			private int cache_index;

			// Token: 0x040005E3 RID: 1507
			private Instruction cache_instruction;
		}
	}
}
